package com.neuedu.mp.framework;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.neuedu.mp.controller.SysUserController;
import com.neuedu.mp.entity.SysMenu;
import com.neuedu.mp.entity.SysUser;
import com.neuedu.mp.service.ISysMenuService;
import org.apache.commons.lang3.ObjectUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.reflect.Method;
import java.util.List;

@Component
@Aspect
//@EnableAspectJAutoProxy
public class SecurityAOP {

    @Autowired
    ISysMenuService menuService;

    @Autowired
    RedisTemplate<String, String> redisTemplate;


    @Autowired
    ObjectMapper objectMapper;


    /**
     * 声明了一个controller的切面
     */
    @Pointcut("execution(* com.neuedu.mp.controller.*.*(..))")
    public void controllerPointCut() {
    }


    //环绕通知
    @Around(value = "controllerPointCut()")
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {

        //验证是否登录


        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        SysUser user = (SysUser) requestAttributes.getAttribute("user", RequestAttributes.SCOPE_REQUEST);


        //判断是否存在权限

//        return 403

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();


        //通过反射获取方法--
//        Method getById = SysUserController.class.getMethod("getById", Integer.class);

        //通过方法查找有没哟AOPAuthorization 注解
        AOPAuthorization annotation = method.getAnnotation(AOPAuthorization.class);
        if (annotation != null) {

            System.out.println("需要验证权限的");


            ValueOperations valueOperations = redisTemplate.opsForValue();

            String key = Constants.USER_MENU_PERS + "_admin";

            String json = (String) valueOperations.get(key);
            List<SysMenu> allPers = null;
            if (ObjectUtils.isEmpty(json)) {
                allPers = menuService.getUserPerms(user.getUserId());

                String jsonPers = objectMapper.writeValueAsString(allPers);

                valueOperations.set(key, jsonPers);

            } else {
                allPers = objectMapper.readValue(json, collectionType(List.class, SysMenu.class));

            }


            //当前用户的菜单权限集合
            String[] menuId = annotation.menuList();
            for (String m : menuId) {
                for (SysMenu sysMenu : allPers) {
                    if (m.equals(sysMenu.getPerms())) {

                        return joinPoint.proceed(joinPoint.getArgs());

                    }
                }
            }

        } else {
            return joinPoint.proceed(joinPoint.getArgs());
        }


        return Ret.forbidden("没有权限访问");


    }


    private JavaType collectionType(Class<?> collectionClz, Class<?>... elementClz) {
        return objectMapper.getTypeFactory().constructParametricType(collectionClz, elementClz);
    }


}
